package cn.git.agent;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.security.ProtectionDomain;

import static net.bytebuddy.matcher.ElementMatchers.*;

/**
 * @description: bytebuddy transform,当被拦截的type第一次要被加载的时候，会进入到此方法
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-12-19
 */
public class MySqlTransform implements AgentBuilder.Transformer {

    /**
     * 拦截的方法
     */
    private static final String INSPECT_EXECUTE_METHOD = "execute";
    private static final String INSPECT_EXECUTE_QUERY = "executeQuery";
    private static final String INSPECT_EXECUTE_UPDATE = "executeUpdate";
    private static final String INSPECT_EXECUTE_LARGE_UPDATE = "executeLargeUpdate";


    /**
     * Allows for a transformation of a {@link DynamicType.Builder}.
     *
     * @param builder
     * @param typeDescription  要被加载的类的信息
     * @param classLoader      The class loader of the instrumented class. Might be {@code null} to represent the bootstrap class loader.
     * @param module           The class's module or {@code null} if the current VM does not support modules.
     * @param protectionDomain The protection domain of the transformed type.
     * @return A transformed version of the supplied {@code builder}.
     */
    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                            TypeDescription typeDescription,
                                            ClassLoader classLoader,
                                            JavaModule module,
                                            ProtectionDomain protectionDomain) {
        // 获取实际的名字
        String actualName = typeDescription.getActualName();
        System.out.println("actualName: " + actualName);

        // 确保匹配的是具体的类，而不是接口
        /**
         *         if (typeDescription.isInterface()) {
         *             System.out.println("接口不拦截");
         *             return builder;
         *         }
         */

        // 实例化 SpringMvcInterceptor
        MySqlInterceptor interceptor = new MySqlInterceptor();

        // 拦截所有被注解标记的方法
        DynamicType.Builder.MethodDefinition.ReceiverTypeDefinition<?> intercept = builder.method(
                        ElementMatchers.namedOneOf(INSPECT_EXECUTE_METHOD,
                                INSPECT_EXECUTE_QUERY,
                                INSPECT_EXECUTE_UPDATE,
                                INSPECT_EXECUTE_LARGE_UPDATE)
                )
                .intercept(MethodDelegation.to(interceptor));
        // 不能返回builder,因为bytebuddy里面的库里面的类基本都是不可变的，修改之后需要返回一个新的builder，避免修改丢失
        return intercept;
    }
}
